from fastapi import APIRouter, HTTPException, Depends, Request, Form, Query, File, UploadFile
from typing import Optional
import tempfile
import os
import json
import logging
import uuid
import time
import traceback
import redis
from fastapi.responses import JSONResponse
import threading

# 导入数据库
from database import get_db_cursor
import database

# 导入必要的工具模块
import cos_utils
from yolo_infer import YoloNoteDetector
from music_parse import parse_symbols_to_stream, stream_to_midi_file
from audio_utils import midi_to_wav

# 设置日志
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)  # 设置为DEBUG级别，输出更多日志信息

# 创建路由器
router = APIRouter(tags=["community"])

# 获取模型路径
MODEL_PATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../music_ocr_model/best.pt'))

# 初始化检测器（在模块级别创建自己的detector实例）
try:
    detector = YoloNoteDetector(MODEL_PATH)
    logger.info(f"成功初始化YoloNoteDetector，模型路径: {MODEL_PATH}")
except Exception as e:
    logger.error(f"初始化YoloNoteDetector失败: {str(e)}")
    logger.error(traceback.format_exc())
    detector = None

# 配置Redis连接 - 用于点赞限制
try:
    redis_client = redis.Redis(host='localhost', port=6379, db=0, decode_responses=True)
    # 测试Redis连接
    redis_client.ping()
    logger.info("成功连接到Redis服务器")
except Exception as e:
    logger.error(f"Redis连接失败: {str(e)}")
    logger.error("将以降级模式运行，不使用Redis缓存")
    redis_client = None

# 定期将Redis点赞数据同步到MySQL
def sync_likes_to_mysql():
    """定期将Redis中的点赞数据同步到MySQL"""
    if not redis_client:
        return
    
    while True:
        try:
            # 每10分钟执行一次同步
            time.sleep(600)
            
            logger.info("开始同步Redis点赞数据到MySQL...")
            
            # 获取所有点赞键
            all_like_keys = redis_client.keys("post_like:*:*")
            
            # 使用数据库连接批量处理
            with database.get_db_cursor(commit=True) as cursor:
                # 统计操作数量
                inserts = 0
                deletes = 0
                
                # 处理每个点赞键
                for key in all_like_keys:
                    try:
                        # 解析键格式 post_like:post_id:user_id
                        parts = key.split(":")
                        if len(parts) != 3:
                            continue
                        
                        post_id = int(parts[1])
                        user_id = int(parts[2])
                        status = redis_client.get(key)
                        
                        if status == "1":
                            # 用户点赞了帖子，确保在MySQL中存在记录
                            query = """
                                INSERT IGNORE INTO post_likes (post_id, user_id)
                                VALUES (%s, %s)
                            """
                            cursor.execute(query, (post_id, user_id))
                            if cursor.rowcount > 0:
                                inserts += 1
                        elif status == "0":
                            # 用户取消了点赞，从MySQL中删除记录
                            query = """
                                DELETE FROM post_likes
                                WHERE post_id = %s AND user_id = %s
                            """
                            cursor.execute(query, (post_id, user_id))
                            if cursor.rowcount > 0:
                                deletes += 1
                    except Exception as e:
                        logger.error(f"处理点赞键 {key} 时出错: {str(e)}")
                
                logger.info(f"Redis点赞数据同步完成: 添加 {inserts} 条, 删除 {deletes} 条")
        except Exception as e:
            logger.error(f"Redis点赞数据同步出错: {str(e)}")
            logger.error(traceback.format_exc())

# 如果Redis连接成功，启动后台同步线程
if redis_client:
    sync_thread = threading.Thread(target=sync_likes_to_mysql, daemon=True)
    sync_thread.start()
    logger.info("已启动Redis点赞数据同步线程")

# 定义可视化函数（避免依赖于utils模块）
def visualize_detections(image_path, symbols, output_path):
    """将检测结果可视化到图像上"""
    try:
        import cv2
        import numpy as np
        
        img = cv2.imread(image_path)
        if img is None:
            logger.error(f"无法读取图像: {image_path}")
            return False
        
        # 每个类别一种颜色
        np.random.seed(42)  # 固定随机种子以使颜色一致
        colors = {}
        
        # 在图像上绘制检测框和标签
        for sym in symbols:
            cls_name = sym['class']
            conf = sym['conf']
            bbox = sym['bbox']
            
            # 为该类别分配一个颜色
            if cls_name not in colors:
                colors[cls_name] = (
                    np.random.randint(0, 255),
                    np.random.randint(0, 255),
                    np.random.randint(0, 255)
                )
            
            color = colors[cls_name]
            x1, y1, x2, y2 = [int(c) for c in bbox]
            
            # 绘制边界框
            cv2.rectangle(img, (x1, y1), (x2, y2), color, 2)
            
            # 准备标签文本
            label = f"{cls_name} {conf:.2f}"
            
            # 计算标签的大小
            (label_width, label_height), baseline = cv2.getTextSize(
                label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
            
            # 绘制标签背景
            cv2.rectangle(
                img, 
                (x1, y1 - label_height - 5), 
                (x1 + label_width, y1), 
                color, 
                -1
            )
            
            # 绘制标签文本
            cv2.putText(
                img, 
                label, 
                (x1, y1 - 5), 
                cv2.FONT_HERSHEY_SIMPLEX, 
                0.5, 
                (255, 255, 255), 
                1
            )
        
        # 保存结果图像
        cv2.imwrite(output_path, img)
        logger.debug(f"可视化结果已保存到: {output_path}")
        return True
    except Exception as e:
        logger.error(f"可视化检测结果失败: {str(e)}")
        logger.error(traceback.format_exc())
        return False

# 为所有响应添加CORS头的辅助函数
def add_cors_headers(response):
    """为响应添加CORS头"""
    if isinstance(response, JSONResponse):
        response.headers["Access-Control-Allow-Origin"] = "*"
        response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
        response.headers["Access-Control-Allow-Headers"] = "*"
        response.headers["Access-Control-Allow-Credentials"] = "true"
    return response

# 添加一个简单的健康检查接口，用于测试路由是否正常工作
@router.get("/health-check")
async def health_check():
    """健康检查接口，用于测试路由是否正常工作"""
    try:
        # 检查是否可以连接数据库
        with database.get_db_cursor() as cursor:
            cursor.execute("SELECT 1")
            result = cursor.fetchone()
        
        # 返回加CORS头的响应
        response = JSONResponse({"status": "ok", "message": "社区模块路由正常工作"})
        return add_cors_headers(response)
    except Exception as e:
        logger.error(f"健康检查失败: {str(e)}")
        error_response = JSONResponse(
            status_code=500,
            content={"status": "error", "message": f"健康检查失败: {str(e)}"}
        )
        return add_cors_headers(error_response)

@router.get("/posts")
async def get_posts(
    limit: int = Query(20, ge=1, le=100),
    offset: int = Query(0, ge=0),
    sort_by: str = Query('latest', regex='^(latest|popular|mixed|followed)$'),
    user_id: Optional[int] = Query(None, description="当前登录用户的ID，用于确定点赞状态"),
    followed_only: bool = Query(False, description="是否只获取关注的用户的帖子")
):
    """获取社区帖子列表，可根据用户ID返回点赞状态，支持获取关注用户的帖子"""
    try:
        logger.info(f"获取帖子列表 - 参数: limit={limit}, offset={offset}, sort_by={sort_by}, user_id={user_id}, followed_only={followed_only}")
        
        # 确保user_id是整数
        if user_id is not None:
            try:
                user_id = int(user_id)
                logger.info(f"转换user_id为整数: {user_id}")
            except (ValueError, TypeError):
                logger.warning(f"无效的user_id格式: {user_id}，设置为None")
                user_id = None
        
        # 如果请求关注内容但没有登录，返回错误
        if followed_only and user_id is None:
            raise HTTPException(status_code=401, detail="请先登录后再查看关注内容")
        
        # 调用数据库函数获取帖子列表，传入user_id以获取点赞状态
        if followed_only:
            posts = database.get_followed_posts(user_id, limit, offset, sort_by)
        else:
            posts = database.get_all_posts(limit, offset, sort_by, user_id)
        
        if posts:
            # 记录首条帖子点赞状态
            first_post = posts[0]
            logger.info(f"首条帖子点赞状态: id={first_post['id']}, liked={first_post.get('liked', False)}, 类型={type(first_post.get('liked', False))}")
            
            # 对标题和内容进行截断处理，限制长度
            title_max_length = 10  # 标题最大长度，超过则截断
            content_max_length = 50  # 内容最大长度，超过则截断
            
            # 确保所有帖子的liked字段是布尔值，并处理日期
            for post in posts:
                post['liked'] = bool(post.get('liked', False))
                logger.debug(f"帖子ID: {post['id']}, 点赞状态: {post['liked']}, 类型: {type(post['liked'])}")
                
                # 截断过长的标题
                if post.get('title') and len(post['title']) > title_max_length:
                    post['title'] = post['title'][:title_max_length] + '...'
                    logger.debug(f"帖子ID: {post['id']}, 标题已截断")
                
                # 截断过长的内容
                if post.get('content') and len(post['content']) > content_max_length:
                    post['content'] = post['content'][:content_max_length] + '...'
                    logger.debug(f"帖子ID: {post['id']}, 内容已截断")
                
                # 添加日期字段，格式化created_at（精确到分钟）
                if post.get('created_at'):
                    post['date'] = post['created_at'].strftime('%Y-%m-%d %H:%M')
                    logger.debug(f"帖子ID: {post['id']}, 日期: {post['date']}, 原始日期: {post['created_at']}")
                
                # 设置音乐预览信息
                if post.get('score_upload_id'):
                    post['musicPreview'] = {
                        'title': post.get('score_title', '未命名乐谱'),
                        'cover': post.get('visualization_url', ''),
                        'audioUrl': post.get('wav_url', None)
                    }
                    logger.debug(f"帖子ID: {post['id']}, 添加乐谱预览: cover={post.get('visualization_url')}")
                
        return posts
    except Exception as e:
        logger.error(f"获取帖子列表异常: {str(e)}")
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail=f"获取帖子列表失败: {str(e)}")

@router.get("/post/{post_id}")
async def get_post_detail(
    post_id: int,
    user_id: Optional[int] = Query(None, description="当前登录用户的ID，用于确定点赞状态")
):
    """获取帖子详情，包括评论，根据用户ID返回点赞状态"""
    try:
        logger.info(f"获取帖子详情 - 帖子ID: {post_id}, 用户ID: {user_id}")
        
        # 调用数据库函数获取帖子详情，传入user_id以获取点赞状态
        post = database.get_post_detail(post_id, user_id)
        
        if not post:
            logger.warning(f"帖子不存在: {post_id}")
            raise HTTPException(status_code=404, detail="帖子不存在")
        
        # 确保liked字段是布尔值
        post['liked'] = bool(post.get('liked', False))
        logger.info(f"帖子详情点赞状态: id={post_id}, liked={post['liked']}, 类型={type(post['liked'])}")
        
        # 处理日期字段，格式化created_at
        if post.get('created_at'):
            post['date'] = post['created_at'].strftime('%Y-%m-%d %H:%M')
            
        # 设置音乐预览信息
        if post.get('score_upload_id'):
            post['musicPreview'] = {
                'title': post.get('score_title', '未命名乐谱'),
                'cover': post.get('visualization_url', ''),
                'audioUrl': post.get('wav_url', None)
            }
        
        # 为评论添加格式化的日期
        if 'commentList' in post and post['commentList']:
            for comment in post['commentList']:
                if comment.get('created_at'):
                    comment['date'] = comment['created_at'].strftime('%Y-%m-%d %H:%M')
                    logger.debug(f"评论ID: {comment['id']}, 格式化日期: {comment['date']}")
        
        return post
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取帖子详情异常: {str(e)}")
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail=f"获取帖子详情失败: {str(e)}")

@router.get("/post-detail/{post_id}")
async def get_post_detail_new(
    post_id: int,
    user_id: Optional[int] = Query(None, description="当前登录用户的ID，用于确定点赞状态")
):
    """获取帖子详情，包括评论，根据用户ID返回点赞状态（新的API路径）"""
    try:
        logger.info(f"新API路径：获取帖子详情 - 帖子ID: {post_id}, 用户ID: {user_id}")
        
        # 调用数据库函数获取帖子详情，传入user_id以获取点赞状态
        post = database.get_post_detail(post_id, user_id)
        
        if not post:
            logger.warning(f"帖子不存在: {post_id}")
            raise HTTPException(status_code=404, detail="帖子不存在")
        
        # 确保liked字段是布尔值
        post['liked'] = bool(post.get('liked', False))
        logger.info(f"帖子详情点赞状态: id={post_id}, liked={post['liked']}, 类型={type(post['liked'])}")
        
        # 处理日期字段，格式化created_at
        if post.get('created_at'):
            post['date'] = post['created_at'].strftime('%Y-%m-%d %H:%M')
            
        # 设置音乐预览信息
        if post.get('score_upload_id'):
            post['musicPreview'] = {
                'title': post.get('score_title', '未命名乐谱'),
                'cover': post.get('visualization_url', ''),
                'audioUrl': post.get('wav_url', None)
            }
        
        # 为评论添加格式化的日期
        if 'commentList' in post and post['commentList']:
            for comment in post['commentList']:
                if comment.get('created_at'):
                    comment['date'] = comment['created_at'].strftime('%Y-%m-%d %H:%M')
                    logger.debug(f"评论ID: {comment['id']}, 格式化日期: {comment['date']}")
        
        return post
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取帖子详情异常: {str(e)}")
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail=f"获取帖子详情失败: {str(e)}")

@router.post("/posts")
async def create_post_alternative(
    request: Request,
    title: str = Form(...),
    content: str = Form(...),
    user_id: int = Form(...),
    score_file: Optional[UploadFile] = File(None)
):
    """创建新帖子（路由别名，提供兼容性支持）"""
    logger.info(f"通过/posts路径创建新帖子 - 标题: {title}, 用户ID: {user_id}")
    # 调用原有的创建帖子函数
    return await create_post(request, title, content, user_id, score_file)

@router.post("/post-create")
async def create_post(
    request: Request,
    title: str = Form(...),
    content: str = Form(...),
    user_id: int = Form(...),
    score_file: Optional[UploadFile] = File(None)
):
    """创建新帖子"""
    logger.info(f"创建新帖子 - 标题: {title}, 用户ID: {user_id}, 上传文件: {'是' if score_file else '否'}")
    try:
        # 检查数据库表是否存在
        with get_db_cursor() as cursor:
            cursor.execute("SHOW TABLES LIKE 'community_posts'")
            if not cursor.fetchone():
                logger.error("community_posts表不存在")
                raise HTTPException(status_code=500, detail="数据库表不存在，无法创建帖子")
        
        score_upload_id = None
        
        # 如果上传了乐谱文件，先处理
        if score_file:
            # 创建临时目录用于处理文件
            with tempfile.TemporaryDirectory() as temp_dir:
                # 保存上传图片到临时目录
                filename = score_file.filename
                local_img_path = os.path.join(temp_dir, filename)
                with open(local_img_path, 'wb') as f:
                    f.write(await score_file.read())
                
                logger.debug(f"已保存上传的文件到: {local_img_path}")
                
                # 生成唯一文件名
                file_prefix = f"{int(time.time())}_{uuid.uuid4().hex[:8]}"
                cloud_filename = f"{file_prefix}_{filename}"
                
                # 使用本模块中的detector进行检测
                if detector:
                    logger.info("开始检测图片中的符号")
                    symbols = detector.detect(local_img_path)
                    logger.info(f"检测到 {len(symbols)} 个符号")
                else:
                    logger.error("检测器未正确初始化，无法处理图片")
                    raise HTTPException(status_code=500, detail="乐谱检测器未初始化")
                
                # 将检测结果保存为JSON
                detection_json = os.path.join(temp_dir, f"{file_prefix}_detections.json")
                detection_json_content = json.dumps(symbols, indent=2)
                with open(detection_json, 'w') as f:
                    f.write(detection_json_content)
                
                # 可视化检测结果
                vis_path = os.path.join(temp_dir, f"{file_prefix}_vis.jpg")
                visualize_result = visualize_detections(local_img_path, symbols, vis_path)
                
                try:
                    # 解析为音符流
                    logger.info("开始解析为音符流")
                    s = parse_symbols_to_stream(symbols)
                    
                    # 生成MIDI
                    midi_path = os.path.join(temp_dir, f"{file_prefix}.mid")
                    stream_to_midi_file(s, midi_path)
                    
                    # 转WAV
                    wav_path = os.path.join(temp_dir, f"{file_prefix}.wav")
                    midi_to_wav(midi_path, wav_path)
                    
                    # 上传文件到腾讯云COS
                    img_cloud_path = f"uploads/images/{cloud_filename}"
                    img_url = cos_utils.upload_file(local_img_path, img_cloud_path)
                    
                    json_cloud_path = f"uploads/json/{file_prefix}_detections.json"
                    json_url = cos_utils.upload_file(detection_json, json_cloud_path)
                    
                    vis_cloud_path = f"uploads/visualizations/{file_prefix}_vis.jpg"
                    vis_url = cos_utils.upload_file(vis_path, vis_cloud_path)
                    
                    midi_cloud_path = f"uploads/midi/{file_prefix}.mid"
                    midi_url = cos_utils.upload_file(midi_path, midi_cloud_path)
                    
                    wav_cloud_path = f"uploads/audio/{file_prefix}.wav"
                    wav_url = cos_utils.upload_file(wav_path, wav_cloud_path)
                    
                    logger.info("所有文件上传完成")
                    
                    # 记录乐谱上传到数据库
                    score_upload_id = database.record_score_upload(
                        user_id,
                        filename,
                        cloud_filename,
                        title,  # 使用帖子标题作为乐谱标题
                        os.path.getsize(local_img_path),
                        'image/jpeg',
                        detection_json_content,
                        img_url,
                        vis_url,
                        json_url
                    )
                    
                    # 记录音频文件到数据库
                    if score_upload_id:
                        logger.info(f"乐谱上传记录创建成功，ID: {score_upload_id}")
                        database.record_audio_files(
                            score_upload_id,
                            f"{file_prefix}.mid",
                            f"{file_prefix}.wav",
                            midi_url,
                            wav_url
                        )
                        
                except Exception as e:
                    logger.error(f"处理乐谱文件时出错: {str(e)}")
                    logger.error(traceback.format_exc())
                    # 如果处理乐谱出错，继续创建帖子，但不关联乐谱
        
        # 创建帖子
        logger.info(f"开始创建帖子 - 标题: {title}, 用户ID: {user_id}, 乐谱ID: {score_upload_id}")
        post_id = database.create_post(user_id, title, content, score_upload_id)
        
        # 获取创建的帖子详情
        post = database.get_post_detail(post_id)
        
        # 处理日期格式
        if post.get('created_at'):
            post['date'] = post['created_at'].strftime('%Y-%m-%d %H:%M')
        
        # 设置音乐预览信息
        if post.get('score_upload_id'):
            post['musicPreview'] = {
                'title': post.get('score_title', '未命名乐谱'),
                'cover': post.get('visualization_url', ''),
                'audioUrl': post.get('wav_url', None)
            }
            
        # 新创建的帖子默认未点赞
        post['liked'] = False
        
        logger.info(f"帖子创建成功，ID: {post_id}")
        return post
    except Exception as e:
        error_msg = f"创建帖子失败: {str(e)}"
        logger.error(error_msg)
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail=error_msg)

@router.post("/post-comment/{post_id}")
async def add_comment(
    post_id: int,
    content: str = Form(...),
    user_id: int = Form(...)
):
    """添加评论"""
    try:
        comment = database.add_post_comment(post_id, user_id, content)
        # 格式化日期
        if comment.get('created_at'):
            comment['date'] = comment['created_at'].strftime('%Y-%m-%d %H:%M')
            logger.debug(f"评论日期格式化: 原始时间={comment['created_at']}, 格式化后={comment['date']}")
        
        return comment
    except Exception as e:
        logger.error(f"添加评论失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"添加评论失败: {str(e)}")

@router.post("/post-like/{post_id}")
async def toggle_like(
    post_id: int,
    user_id: int = Form(...)
):
    """切换帖子的点赞状态 (点赞/取消点赞)"""
    try:
        logger.info(f"切换帖子点赞状态 - post_id: {post_id}, user_id: {user_id}")
        
        # 检查帖子是否存在
        with get_db_cursor() as cursor:
            cursor.execute("SELECT * FROM community_posts WHERE id = %s", (post_id,))
            post = cursor.fetchone()
            
            if not post:
                logger.warning(f"帖子不存在 - post_id: {post_id}")
                raise HTTPException(status_code=404, detail="帖子不存在")
        
        # 如果Redis可用，使用Redis进行点赞限制和计数器
        if redis_client:
            # 键格式: post_like:post_id:user_id
            key = f"post_like:{post_id}:{user_id}"
            
            # 检查当前点赞状态
            current_status = redis_client.get(key)
            
            # 切换点赞状态
            if current_status == "1":
                # 已点赞，切换为取消点赞
                new_status = "0"
                operation = "取消点赞"
                mysql_operation = "DELETE"
            else:
                # 未点赞或首次点赞，切换为点赞
                new_status = "1"
                operation = "点赞"
                mysql_operation = "INSERT"
            
            # 更新Redis中的点赞状态（设置24小时过期，过期前会被同步线程同步到MySQL）
            redis_client.set(key, new_status, ex=86400)
            
            # 更新帖子的点赞计数器（减少MySQL查询负担）
            likes_count_key = f"post_likes_count:{post_id}"
            
            # 获取当前点赞数
            current_count = redis_client.get(likes_count_key)
            
            if current_count is None:
                # 如果缓存未命中，从MySQL获取
                with get_db_cursor() as cursor:
                    cursor.execute(
                        "SELECT COUNT(*) FROM post_likes WHERE post_id = %s",
                        (post_id,)
                    )
                    result = cursor.fetchone()
                    # 根据不同的返回格式正确获取计数
                    if isinstance(result, dict):
                        # 如果结果是字典形式(DictCursor)
                        current_count = result['COUNT(*)'] if 'COUNT(*)' in result else list(result.values())[0]
                    else:
                        # 如果结果是元组形式
                        current_count = result[0]
                    
                    logger.debug(f"从MySQL获取点赞数: {current_count}, 类型: {type(current_count)}")
                # 将结果写入Redis
                redis_client.set(likes_count_key, current_count, ex=3600)  # 1小时过期
            else:
                current_count = int(current_count)
            
            # 更新计数器
            if new_status == "1":
                new_count = current_count + 1
            else:
                new_count = max(0, current_count - 1)  # 确保不会小于0
            
            # 更新Redis中的计数器
            redis_client.set(likes_count_key, new_count, ex=3600)  # 1小时过期
            
            # 检查是否需要立即更新MySQL
            need_update_db = True
            
            # 如果需要立即更新MySQL，执行相应的操作
            if need_update_db:
                with get_db_cursor(commit=True) as cursor:
                    if mysql_operation == "INSERT":
                        # 插入点赞记录（使用IGNORE以防重复）
                        cursor.execute(
                            "INSERT IGNORE INTO post_likes (post_id, user_id) VALUES (%s, %s)",
                            (post_id, user_id)
                        )
                    else:  # DELETE
                        # 删除点赞记录
                        cursor.execute(
                            "DELETE FROM post_likes WHERE post_id = %s AND user_id = %s",
                            (post_id, user_id)
                        )
            
            logger.info(f"成功{operation}帖子 - post_id: {post_id}, user_id: {user_id}, 点赞数: {new_count}")
            
            # 返回新的点赞状态和点赞数
            return {
                "liked": new_status == "1",
                "like_count": new_count
            }
        else:
            # Redis不可用，直接使用MySQL
            with get_db_cursor(commit=True) as cursor:
                # 检查用户是否已经点赞过该帖子
                cursor.execute(
                    "SELECT * FROM post_likes WHERE post_id = %s AND user_id = %s",
                    (post_id, user_id)
                )
                liked = cursor.fetchone() is not None
                
                if liked:
                    # 如果已点赞，则取消点赞
                    cursor.execute(
                        "DELETE FROM post_likes WHERE post_id = %s AND user_id = %s",
                        (post_id, user_id)
                    )
                    operation = "取消点赞"
                else:
                    # 如果未点赞，则添加点赞
                    cursor.execute(
                        "INSERT INTO post_likes (post_id, user_id) VALUES (%s, %s)",
                        (post_id, user_id)
                    )
                    operation = "点赞"
                
                # 获取更新后的点赞数量
                cursor.execute(
                    "SELECT COUNT(*) FROM post_likes WHERE post_id = %s",
                    (post_id,)
                )
                result = cursor.fetchone()
                # 根据不同的返回格式正确获取计数
                if isinstance(result, dict):
                    # 如果结果是字典形式(DictCursor)
                    like_count = result['COUNT(*)'] if 'COUNT(*)' in result else list(result.values())[0]
                else:
                    # 如果结果是元组形式
                    like_count = result[0]
                
                logger.info(f"成功{operation}帖子 - post_id: {post_id}, user_id: {user_id}, 点赞数: {like_count}")
                
                # 返回新的点赞状态和点赞数
                return {
                    "liked": not liked,
                    "like_count": like_count
                }
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"切换帖子点赞状态失败: {str(e)}")
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail=f"切换点赞状态失败: {str(e)}")

@router.get("/post-like-status/{post_id}")
async def get_post_like_status(
    post_id: int,
    user_id: Optional[int] = Query(None, description="当前登录用户的ID，用于确定点赞状态")
):
    """获取用户对特定帖子的点赞状态"""
    try:
        logger.info(f"获取帖子点赞状态 - post_id: {post_id}, user_id: {user_id}")
        
        # 如果用户未登录，无需查询点赞状态
        if user_id is None:
            logger.info("用户未登录，无需查询点赞状态")
            return {
                "liked": False,
                "like_count": database.get_post_likes_count(post_id)
            }
        
        # 确保user_id是整数
        try:
            user_id = int(user_id)
        except (ValueError, TypeError):
            logger.warning(f"无效的user_id格式: {user_id}")
            return {
                "liked": False,
                "like_count": database.get_post_likes_count(post_id)
            }
        
        # 检查帖子是否存在
        with get_db_cursor() as cursor:
            cursor.execute("SELECT * FROM community_posts WHERE id = %s", (post_id,))
            post = cursor.fetchone()
            
            if not post:
                logger.warning(f"帖子不存在 - post_id: {post_id}")
                raise HTTPException(status_code=404, detail="帖子不存在")
        
        # 如果Redis可用，从Redis中获取点赞状态
        if redis_client:
            # 键格式: post_like:post_id:user_id
            key = f"post_like:{post_id}:{user_id}"
            
            # 获取点赞状态
            status = redis_client.get(key)
            liked = status == "1"
            
            # 获取帖子的点赞计数
            likes_count_key = f"post_likes_count:{post_id}"
            current_count = redis_client.get(likes_count_key)
            
            if current_count is None:
                # 如果缓存未命中，从MySQL获取
                with get_db_cursor() as cursor:
                    cursor.execute(
                        "SELECT COUNT(*) FROM post_likes WHERE post_id = %s",
                        (post_id,)
                    )
                    result = cursor.fetchone()
                    # 根据不同的返回格式正确获取计数
                    if isinstance(result, dict):
                        # 如果结果是字典形式(DictCursor)
                        current_count = result['COUNT(*)'] if 'COUNT(*)' in result else list(result.values())[0]
                    else:
                        # 如果结果是元组形式
                        current_count = result[0]
                    
                    logger.debug(f"从MySQL获取点赞数: {current_count}, 类型: {type(current_count)}")
                # 将结果写入Redis
                redis_client.set(likes_count_key, current_count, ex=3600)  # 1小时过期
            else:
                current_count = int(current_count)
        else:
            # Redis不可用，直接使用MySQL
            liked = database.check_post_like_status(post_id, user_id)
            current_count = database.get_post_likes_count(post_id)
        
        logger.info(f"帖子点赞状态 - post_id: {post_id}, user_id: {user_id}, liked: {liked}, like_count: {current_count}")
        
        return {
            "liked": liked,
            "like_count": current_count
        }
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取帖子点赞状态失败: {str(e)}")
        logger.error(traceback.format_exc())
        raise HTTPException(status_code=500, detail=f"获取点赞状态失败: {str(e)}")

@router.delete("/post-delete/{post_id}")
async def delete_post(
    post_id: int,
    user_id: int = Query(...)
):
    """删除帖子"""
    try:
        success, message = database.delete_post(post_id, user_id)
        if not success:
            raise HTTPException(status_code=403, detail=message)
        
        return {"message": message}
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除帖子失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"删除帖子失败: {str(e)}")

# 获取社区帖子音频
@router.get("/post-audio/{score_upload_id}")
async def get_post_audio(score_upload_id: int):
    """获取帖子关联的音频"""
    try:
        # 查询数据库获取音频信息
        with database.get_db_cursor() as cursor:
            sql = """
                SELECT wav_url, midi_url
                FROM audio_files
                WHERE score_upload_id = %s
            """
            cursor.execute(sql, (score_upload_id,))
            audio = cursor.fetchone()
            
            if not audio or not audio.get('wav_url'):
                raise HTTPException(status_code=404, detail="音频不存在")
            
            return {"audio_url": audio['wav_url']}
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取音频失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取音频失败: {str(e)}")

# 关注用户API
@router.post("/user-follow/{followed_id}")
async def follow_user_api(followed_id: int, follower_id: int = Form(...)):
    """关注用户"""
    try:
        success, message = database.follow_user(follower_id, followed_id)
        if not success:
            raise HTTPException(status_code=400, detail=message)
        
        return {"message": message}
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"关注用户失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"关注用户失败: {str(e)}")

@router.post("/user-unfollow/{followed_id}")
async def unfollow_user_api(followed_id: int, follower_id: int = Form(...)):
    """取消关注用户"""
    try:
        success, message = database.unfollow_user(follower_id, followed_id)
        if not success:
            raise HTTPException(status_code=400, detail=message)
        
        return {"message": message}
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"取消关注用户失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"取消关注用户失败: {str(e)}")

@router.get("/follow-status/{followed_id}")
async def check_follow_status_api(followed_id: int, follower_id: int = Query(...)):
    """检查是否关注了指定用户"""
    try:
        is_following = database.check_follow_status(follower_id, followed_id)
        return {"following": is_following}
    except Exception as e:
        logger.error(f"检查关注状态失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"检查关注状态失败: {str(e)}")

@router.get("/user-followers/{user_id}")
async def get_user_followers_api(user_id: int):
    """获取用户的关注者列表"""
    try:
        followers = database.get_user_followers(user_id)
        return followers
    except Exception as e:
        logger.error(f"获取关注者列表失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取关注者列表失败: {str(e)}")

@router.get("/user-following/{user_id}")
async def get_user_following_api(user_id: int):
    """获取用户关注的人列表"""
    try:
        following = database.get_user_following(user_id)
        return following
    except Exception as e:
        logger.error(f"获取关注列表失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取关注列表失败: {str(e)}")

# 处理CORS预检请求
@router.options("/{path:path}")
async def options_handler(path: str):
    """处理所有OPTIONS预检请求，返回正确的CORS头信息"""
    response = JSONResponse({})
    response.headers["Access-Control-Allow-Origin"] = "*"
    response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
    response.headers["Access-Control-Allow-Headers"] = "*"
    response.headers["Access-Control-Allow-Credentials"] = "true"
    return response 